#pragma once
#ifndef xRes_h__
#define xRes_h__
#include "../../../dxhead/dxegheader.h"
#include "../../../../myLib/myLib.h"

#pragma warning( push )
#pragma warning(disable:4995)
#include <list>
#pragma warning(pop) 
namespace Sky
{
	class xDxApp;
	class xDevice;
	class xAppResBase : public Sky::Object
	{
	private:
		typedef std::list<xAppResBase*> xResList;
	protected:
		TVoid*  getResAddr(){return resPtr;};
		TVoid	setResAddr(TVoid* addr){resPtr = addr;}
		TVoid	setxIApp(xDxApp* app){xGlobal<xDxApp*>::set(app);}
		xDxApp*  getxIApp(){return xGlobal<xDxApp*>::get();}
	public:
		virtual TResult Create(xDxApp* app) = 0;
		virtual TResult Delete(xDxApp* app) = 0;
		virtual TResult trySelfCreate() = 0;
	public:
		static TVoid	addToList(xAppResBase* res){xGlobal<xResList>::get().push_back(res);}
		static TVoid	delFromList(xAppResBase* res){xGlobal<xResList>::get().remove(res);}
		static TVoid	invokeCreate(xDxApp* app);
		static TVoid	invokeDelete(xDxApp* app);
			
	protected:
		TVoid* resPtr;
	};
	class xDevResBase : public xAppResBase
	{
	private:
		typedef std::list<xDevResBase*> xDevResList;
	public:
		static TVoid	addToList(xDevResBase* res){xGlobal<xDevResList>::get().push_back(res);}
		static TVoid	delFromList(xDevResBase* res){xGlobal<xDevResList>::get().remove(res);}
		static TVoid	invokeCreate(xDevice* dev);
		static TVoid	invokeDelete(xDevice* dev);
		static TVoid	invokeLost(xDevice* dev);
		static TVoid	invokeReset(xDevice* dev);
	public:
		virtual TResult Create(xDevice* dev) = 0;
		virtual TResult Reset(xDevice* dev) = 0;
		virtual TResult Lost(xDevice* dev) = 0;
		virtual TResult Delete(xDevice* dev) = 0;
	protected:
		virtual TResult onCreate(xDxApp* app) = 0;
		virtual TResult onDelete(xDxApp* app) = 0;
		virtual TResult onCreate(xDevice* dev) = 0;
		virtual TResult onReset(xDevice* dev) = 0;
		virtual TResult onLost(xDevice* dev) = 0;
		virtual TResult onDelete(xDevice* dev) = 0;
	};
	//////////////////////////////////////////////////////////////////////////
	template <typename TClass>
	class xAppRes :public xAppResBase
	{
	public:
		xAppRes():m_Res(vNull),m_bCreateByAppCalled(vFalse),m_bCreateByAppSucced(vFalse){setResAddr((TVoid*)&m_Res);}
		TClass	getCreatedRes()
		{
			if(m_Res != vNull)
				return m_Res;
			trySelfCreate();
			return m_Res;
		}
	public:
		virtual TResult trySelfCreate()
		{
			if(m_bCreateByAppCalled){
				return XE_ALREADYERROR;
			} 
			else
			{
				myDeV_Ret_M(Create(getxIApp()));
			}
			return XE_OK;
		}
		virtual TResult Create(xDxApp* app)
		{
			TResult hr;
			if(!m_bCreateByAppCalled)
			{
				m_bCreateByAppCalled = vTrue;
				hr = onCreate(app);
				if(hr == XE_OK){
					m_bCreateByAppSucced = vTrue;
				}else 
					return hr;
			}
			return XE_OK;
		}
		virtual TResult Delete(xDxApp* app)
		{
			if(m_bCreateByAppSucced)
			{
				m_bCreateByAppCalled = vFalse;
				m_bCreateByAppSucced = vFalse;
				return onDelete(app);
			}
			return XE_OK;
		}
	protected:
		virtual TResult onCreate(xDxApp* app) = 0;
		virtual TResult onDelete(xDxApp* app) = 0;
	protected:
		TClass m_Res;
		TBool  m_bCreateByAppCalled;
		TBool  m_bCreateByAppSucced;
	};
	//////////////////////////////////////////////////////////////////////////
	template <typename TClass>
	class xDeviceRes : public xDevResBase
	{
	public:
		xDeviceRes():m_Res(vNull),m_bCreateByDevCalled(vFalse),m_bCreateByDevSucced(vFalse),m_bCreateByAppCalled(vFalse),m_bCreateByAppSucced(vFalse){setResAddr((TVoid*)&m_Res);}
		TClass	getCreatedRes()
		{
			if(m_Res != vNull)
				return m_Res;
			trySelfCreate();
			return m_Res;
		}
		TResult Create(xDxApp* app)
		{
			TResult hr;
			if(!m_bCreateByAppCalled)
			{
				m_bCreateByAppCalled = vTrue;
				hr = onCreate(app);
				if(hr == XE_OK){
					m_bCreateByAppSucced = vTrue;
				}else
					return hr;
			}
			hr = Create(app->getDevice());
			if(FAILED(hr))return hr;
			else {
				addToList(this);
			}
			return XE_OK;
		}
		TResult Delete(xDxApp* app)
		{
			Delete(app->getDevice());
			if(m_bCreateByDevSucced)
			{
				m_bCreateByAppCalled = vFalse;
				m_bCreateByAppSucced = vFalse;
				delFromList(this);
				return onDelete(app);
			}
			return XE_OK;
		}
		TResult Create(xDevice* dev)
		{
			TResult hr;
			if(!m_bCreateByDevCalled)
			{
				m_bCreateByDevCalled = vTrue;
				hr = onCreate(dev);
				if(XE_OK == hr){
					m_bCreateByDevSucced = vTrue;
				}else
					return hr;
			}
			return XE_OK;
		}
		TResult Reset(xDevice* dev)
		{
			if(m_bCreateByDevSucced)
			{
				return onReset(dev);
			}
			return XE_OK;
		}
		TResult Lost(xDevice* dev)
		{
			if(m_bCreateByDevSucced)
			{
				return onLost(dev);
			}
			return XE_OK;
		}
		TResult Delete(xDevice* dev)
		{
			m_bCreateByDevCalled = vFalse;
			m_bCreateByDevSucced = vFalse;
			return onDelete(dev);
		} // if(m_bCreateByDevSucced)
	public:
		virtual TResult trySelfCreate()
		{
			if(m_bCreateByAppCalled){
				myTrace0A(E,"getCreatedRes() failed");
				return XE_ALREADYERROR;
			} // if(m_bCreateByAppCalled)
			else
			{
				myDeV_Ret_M(Create(getxIApp()));
			}
			return XE_OK;
		}
	protected:
		virtual TResult onCreate(xDxApp* app) = 0;
		virtual TResult onDelete(xDxApp* app) = 0;
		virtual TResult onCreate(xDevice* dev) = 0;
		virtual TResult onReset(xDevice* dev) = 0;
		virtual TResult onLost(xDevice* dev) = 0;
		virtual TResult onDelete(xDevice* dev) = 0;
	protected:
		TClass m_Res;
		TBool  m_bCreateByDevCalled;
		TBool  m_bCreateByDevSucced;
		TBool  m_bCreateByAppCalled;
		TBool  m_bCreateByAppSucced;
	};
}
#endif // xRes_h__